/*
    完成日志器模块：
        1. 抽象日志器基类
        2. 派生出不同的子类（同步日志器类 & 异步日志器类）
*/

#ifndef __M_LOGGER__H__
#define __M_LOGGER__H__

#include "util.hpp"
#include "format.hpp"
#include "level.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <cstdio>

namespace Log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string loggername,LogLevel::Value level,Formatter::ptr formatter,std::vector<LogSink::prt> sinks)
            :_logger_name(loggername)
            ,_level(level)
            ,_formatter(formatter)
            ,_sinks(sinks.begin(),sinks.end())
        {}
        const std::string& name()
        {
            return _logger_name;
        }
        void Debug(std::string file,size_t line,const char* fmt,...)
        {
            // 1. 判断当前的日志是否达到了输出等级
            if(_level > LogLevel::Value::DEBUG) return;

            // 2. 对fmt格式化字符串和不定参数进行字符串组织
            va_list al;
            va_start(al,fmt);
            Serialize(LogLevel::Value::DEBUG,line,file,fmt,al);
            va_end(al);
        }
        void Info(std::string file,size_t line,const char* fmt,...)
        {
            // 1. 判断当前的日志是否达到了输出等级
            if(_level > LogLevel::Value::INFO) return;

            // 2. 对fmt格式化字符串和不定参数进行字符串组织
            va_list al;
            va_start(al,fmt);
            Serialize(LogLevel::Value::INFO,line,file,fmt,al);
            va_end(al);
        }
        void Warn(std::string file,size_t line,const char* fmt,...)
        {
            // 1. 判断当前的日志是否达到了输出等级
            if(_level > LogLevel::Value::WARN) return;

            // 2. 对fmt格式化字符串和不定参数进行字符串组织
            va_list al;
            va_start(al,fmt);
            Serialize(LogLevel::Value::WARN,line,file,fmt,al);
            va_end(al);
        }
        void Error(std::string file,size_t line,const char* fmt,...)
        {
            // 1. 判断当前的日志是否达到了输出等级
            if(_level > LogLevel::Value::ERROR) return;

            // 2. 对fmt格式化字符串和不定参数进行字符串组织
            va_list al;
            va_start(al,fmt);
            Serialize(LogLevel::Value::ERROR,line,file,fmt,al);
            va_end(al);
        }
        void Fatal(std::string file,size_t line,const char* fmt,...)
        {
            // 1. 判断当前的日志是否达到了输出等级
            if(_level > LogLevel::Value::FATAL) return;

            // 2. 对fmt格式化字符串和不定参数进行字符串组织
            va_list al;
            va_start(al,fmt);
            Serialize(LogLevel::Value::FATAL,line,file,fmt,al);
            va_end(al);
        }
    protected:
        // 序列化字符串
        void Serialize(LogLevel::Value level,size_t line,std::string file,const char* msg,va_list al)
        {
            char* res;
            int ret = vasprintf(&res,msg,al);
            if(ret < 0)
            {
                std::cout << "vasprintf failed\n" << std::endl;
                return;
            }

            // 3. 构造LogMsg对象
            LogMsg text(level,line,file,_logger_name,res);

            // 4. 通过格式化工具对LogMsg进行格式化
            std::stringstream ss;
            _formatter->format(ss,text);
            
           // std::cout << ss.str() << std::endl;
            // 5. 进行日志落地
            Log(ss.str());
            free(res);
        }
        virtual void Log(std::string msg) = 0;
    protected:
        std::mutex _mutex;                  // 用于加锁
        std::string _logger_name;           // 日志器名称
        std::atomic<LogLevel::Value> _level;// 日志等级
        Formatter::ptr _formatter;         // 控制格式化
        std::vector<LogSink::prt> _sinks;   // 日志的落地方式
    };

    // 在落地时，同步日志器使用单线程，异步日志器使用多线程，所以在这方面各自设置
    // 同步日志器
    class SyncLogger:public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string loggername,
            LogLevel::Value level,
            Formatter::ptr formatter,
            std::vector<LogSink::prt> sinks)
            :Logger(loggername,level,formatter,sinks)
        {
           // std::cout << sinks.size() << std::endl;
        }
    protected:
        void Log(std::string msg)override
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            if(_sinks.empty()) 
                return;
                
            for(auto& sink:_sinks)
            {
                sink->log(msg);
            }
        }
    };

    // 异步日志器
    class AsyncLogger:public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        AsyncLogger(const std::string loggername,
            LogLevel::Value level,
            Formatter::ptr formatter,
            std::vector<LogSink::prt> sinks,
            AsyncType loop_type)
            :Logger(loggername,level,formatter,sinks)
            ,_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::RealLog,this,std::placeholders::_1),loop_type))
            // 一定要指明所用的是类内函数，否则编译器会认为这是全局函数
        {}
    protected:
        void Log(std::string msg)override
        {
            _looper->push(msg.c_str(),msg.size());
        }

        void RealLog(Buffer& buf)
        {
            if(_sinks.empty())
                return;
            
            for(auto& sink:_sinks)
            {
                sink->log(std::string(buf.begin(),buf.readAbleSize()));
            }
        }
    private:
        AsyncLooper::prt _looper;
    };
}



#endif